package com.cmcc.waf.report.utils;
/*------------------------------------------------------------------------------
 *******************************************************************************
 * COPYRIGHT China Mobile (SuZhou) Software Technology Co.,Ltd. 2020
 *
 * The copyright to the computer program(s) herein is the property of
 * CMSS Co.,Ltd. The programs may be used and/or copied only with written
 * permission from CMSS Co.,Ltd. or in accordance with the terms and conditions
 * stipulated in the agreement/contract under which the program(s) have been
 * supplied.
 *******************************************************************************
 *----------------------------------------------------------------------------*/

import cn.hutool.core.util.HexUtil;
import com.cmcc.waf.report.core.exception.BusinessException;
import feign.RequestTemplate;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;

@Slf4j
public class OpSignatureUtil {

    private static final Logger logger = LoggerFactory.getLogger(OpSignatureUtil.class);

    private static final String URL_ENCODER_FORMATE = "%s=%s";

    public static void getSignature(RequestTemplate template, String accessKey, String secretKey) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
        try {
            final Map<String, Object> query = new HashMap<>(8);
            Map<String, Collection<String>> queryMap = template.queries();
            if (!Objects.isNull(queryMap)) {
                for (Map.Entry<String, Collection<String>> entry : queryMap.entrySet()) {
                    Collection<String> value = entry.getValue();

                    if (value.size() != 1) {
                        logger.error("url拼接参数暂不支持数组:{}", value);
                        throw new BusinessException("url拼接参数暂不支持数组");
                    }
                    query.put(entry.getKey(), entry.getValue().toArray()[0]);
                }
            }

            query.put("AccessKey", accessKey);
            query.put("Timestamp", sdf.format(new Date()));
            query.put("SignatureNonce",  UUID.randomUUID().toString().replace("-", ""));
            query.put("SignatureVersion", "V2.0");
            query.put("SignatureMethod", "HmacSHA1");
            ArrayList<String> parameterList = new ArrayList();
            parameterList.addAll(query.keySet());
            Collections.sort(parameterList);
            List<String> list = new ArrayList(query.size());
            Iterator iterator = parameterList.iterator();

            String name;
            while (iterator.hasNext()) {
                name = (String) iterator.next();
                if (!"Signature".equalsIgnoreCase(name)) {
                    String value = "";

                    try {
                        value = query.get(name).toString();
                    } catch (ClassCastException var11) {
                        if (query.get(name) instanceof Boolean) {
                            if ((Boolean) query.get(name)) {
                                value = "true";
                            } else {
                                value = "false";
                            }
                        }
                    }

                    list.add(String.format(URL_ENCODER_FORMATE, percentEncode(name), percentEncode(value)));
                }
            }

            String canonicalizedQueryString = StringUtils.join(list, "&");

            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(canonicalizedQueryString.getBytes("utf-8"));
            name =  HexUtil.encodeHexStr(hash);
            StringBuilder sb = new StringBuilder();
            if (Objects.isNull(template.method())) {
                throw new BusinessException("网关url签名失败");
            }
            sb.append(template.method().toUpperCase());
            sb.append("\n");
            String path = template.path();
            sb.append(percentEncode(path));
            sb.append("\n");
            sb.append(name);

            String signature = sign("BC_SIGNATURE&" + secretKey, sb.toString());
            if (StringUtils.isEmpty(signature)) {
                throw new BusinessException("签名生成失败");
            } else {
                query.put("Signature", percentEncode(signature));
            }
            template.queries(null);

            parameterList.add(1, "Signature");
            for (String s : parameterList) {
                template.query(s, (String) query.get(s));
            }
        } catch (UnsupportedEncodingException | NoSuchAlgorithmException e) {
            throw new BusinessException("网关url签名失败", e);
        }
    }
    public static String percentEncode(String value) throws UnsupportedEncodingException {
        return value != null ? URLEncoder.encode(value, "utf-8").replace("+", "%20").replace("*", "%2A").replace("%7E", "~") : null;
    }

    public static String sign(String secretKey, String data) {
        try {
            Mac mac = Mac.getInstance("HmacSHA1");
            byte[] secretKeyByte = secretKey.getBytes("utf-8");
            SecretKeySpec secretKeySpec = new SecretKeySpec(secretKeyByte, "HmacSHA1");
            mac.init(secretKeySpec);
            return HexUtil.encodeHexStr(mac.doFinal(data.getBytes("utf-8")));
        } catch (InvalidKeyException | UnsupportedEncodingException | NoSuchAlgorithmException var5) {
            return null;
        }
    }
}
